package com.cy.container;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author ChenYan
 * @Date 2021/8/13 15:22
 * @Description
 */
public class Mapper {

    private List<MappedHost> hosts = new ArrayList<>();

    public void addHost(String name, Host host){
        MappedHost mappedHost = new MappedHost(name, host);
        hosts.add(mappedHost);
    }

    public void addContext(String hostName, Host host, String contextName, Context context){
        MappedContext mappedContext = new MappedContext(contextName, context);
        MappedHost mappedHost = findHosts(hosts, hostName);

        if (mappedHost == null){
            addHost(hostName, host);
            mappedHost = findHosts(hosts, hostName);
        }
        mappedHost.mappedContexts.put(contextName, mappedContext);
    }

    private MappedHost findHosts(List<MappedHost> hosts, String hostName) {
        for (MappedHost host : hosts) {
            if (host.name.equals(hostName)){
                return host;
            }
        }
        return null;
    }

    public void addWrapper(String hostName, Host host, String contextName, Context context, String wrapperName, Wrapper wrapper){
        MappedWrapper mappedWrapper = new MappedWrapper(wrapperName, wrapper);

        MappedHost mappedHost = findHosts(hosts, hostName);
        if (mappedHost == null){
            addHost(hostName, host);
            mappedHost = findHosts(hosts, hostName);
        }

        MappedContext mappedContext = mappedHost.mappedContexts.get(contextName);
        if (mappedContext == null){
            addContext(hostName, host, contextName, context);
            mappedContext = mappedHost.mappedContexts.get(contextName);
        }

        mappedContext.mappedWrappers.put(wrapperName, mappedWrapper);
    }


    private static final <T, E extends MapElement<T>> E exactFind(E[] map, String name) {
        int pos = find(map, name);
        if (pos >= 0) {
            E result = map[pos];
            if (name.equals(result.name)) {
                return result;
            }
        }
        return null;
    }

    /**
     * 递归查找
     * @param map
     * @param name
     * @param <T>
     * @return
     */
    private static final <T> int find(MapElement<T>[] map, String name) {

        int a = 0;
        int b = map.length - 1;

        // Special cases: -1 and 0
        if (b == -1) {
            return -1;
        }

        if (name.compareTo(map[0].name) < 0) {
            return -1;
        }
        if (b == 0) {
            return 0;
        }

        int i = 0;
        while (true) {
            i = (b + a) >>> 1;
            int result = name.compareTo(map[i].name);
            if (result > 0) {
                a = i;
            } else if (result == 0) {
                return i;
            } else {
                b = i;
            }
            if ((b - a) == 1) {
                int result2 = name.compareTo(map[b].name);
                if (result2 < 0) {
                    return a;
                } else {
                    return b;
                }
            }
        }

    }

    public Wrapper findWrapperByUrl(String url) {
        //http://localhost:8080/test1/servlet1...
        //url = /test1/servlet1
        //[0] =
        //[1] = test1
        //[2] = servlet1
        String[] urlElement = url.split("/");
        String contextName = null;
        String wrapperName = null;
        if (urlElement.length > 1){
            contextName = urlElement[1];
        }
        if (urlElement.length > 2){
            wrapperName = "/"+urlElement[2];
        }
        MappedContext mappedContext = null;
        if (contextName != null){
            for (MappedHost host : hosts) {
                mappedContext = host.getMappedContexts().get(contextName);
            }
            if (mappedContext == null){
                return null;
            }
        }
        if (mappedContext != null){
            if (wrapperName == null){
                //如果为空，自动找默认的
                wrapperName = "/";
            }
            MappedWrapper mappedWrapper = mappedContext.getMappedWrappers().get(wrapperName);
            if (mappedWrapper != null){
                return mappedWrapper.object;
            }
        }
        return null;
    }

    protected abstract static class MapElement<T> {
        public final String name;
        public final T object;

        public MapElement(String name, T object) {
            this.name = name;
            this.object = object;
        }
    }

    protected static final class MappedHost extends MapElement<Host>{

        private Map<String, MappedContext> mappedContexts = new HashMap<>();

        public MappedHost(String name, Host object) {
            super(name, object);
        }

        /**
         * Gets the value of mappedContexts. *
         *
         * @return the value of mappedContexts
         */
        public Map<String, MappedContext> getMappedContexts() {
            return mappedContexts;
        }
    }

    protected static final class MappedContext extends MapElement<Context>{

        private Map<String, MappedWrapper> mappedWrappers = new HashMap<>();

        public MappedContext(String name, Context object) {
            super(name, object);
        }

        /**
         * Gets the value of mappedWrappers. *
         *
         * @return the value of mappedWrappers
         */
        public Map<String, MappedWrapper> getMappedWrappers() {
            return mappedWrappers;
        }
    }

    protected static final class MappedWrapper extends MapElement<Wrapper>{

        public MappedWrapper(String name, Wrapper object) {
            super(name, object);
        }
    }
}
